import React, { useState, useEffect, useRef } from 'react';
import {
  Select,
  MenuItem,
  Box,
  InputLabel,
  FormControl,
  styled,
} from '@mui/material';
import { NetPyNEField, ListComponent, NetPyNETextField } from '../../../components';
import Utils from '../../../utils/Utils';

const StyledContainer = styled('div')({
  width: '100%',
});

const StyledField = styled(Box)(({ theme }) => ({
  width: '95% !important',
  marginLeft: theme.spacing(3),
}));

interface DimensionsProps {
  modelName: string;
  dimensionType?: string;
  callback?: () => void;
  updateCards?: () => void;
}

interface PopDimensionOption {
  label: string;
  value: string;
}

const popDimensionsOptions: PopDimensionOption[] = [
  {
    label: 'Number of cells',
    value: 'numCells',
  },
  {
    label: 'Density',
    value: 'density',
  },
  {
    label: 'Grid spacing',
    value: 'gridSpacing',
  },
  {
    label: 'Cell List',
    value: 'cellsList',
  },
];

/**
 * Dimensions Component
 * Population dimension configuration component
 */
const Dimensions: React.FC<DimensionsProps> = ({
  modelName,
  dimensionType,
  callback,
  updateCards,
}) => {
  const [dimension, setDimension] = useState<string>('numCells');
  const mountedRef = useRef(true);
  const updateTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);

  useEffect(() => {
    mountedRef.current = true;
    updateLayout();

    return () => {
      mountedRef.current = false;
      if (updateTimerRef.current) {
        clearTimeout(updateTimerRef.current);
      }
    };
  }, []);

  useEffect(() => {
    updateLayout();
  }, [modelName]);

  const updateLayout = (): void => {
    const requests = popDimensionsOptions.map((popDimensionsOption) =>
      // Check if dimension option exists in Python model
      Utils.evalPythonMessage(
        `'${popDimensionsOption.value}' in netpyne_geppetto.netParams.popParams['${modelName}']`,
        []
      ),
    );

    // Get population dimension by asking each for each key
    Promise.all(requests)
      .then((values) => {
        const index = values.indexOf(true);
        if (mountedRef.current) {
          if (index === -1) {
            setDimension('numCells');
          } else {
            setDimension(popDimensionsOptions[index].value);
          }
        }
      })
      .catch((error) => {
        console.error('Error updating layout:', error);
        if (mountedRef.current) {
          setDimension('numCells');
        }
      });
  };

  const triggerUpdate = (updateMethod: () => void): void => {
    // Common strategy when triggering processing of a value change, delay it
    if (updateTimerRef.current !== undefined) {
      clearTimeout(updateTimerRef.current);
    }
    updateTimerRef.current = setTimeout(updateMethod, 500);
  };

  const handleDimValueChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
    let newValue: number | string =
      event.target.type === 'number'
        ? parseFloat(event.target.value)
        : event.target.value;
    // Update State
    if (Number.isNaN(newValue)) {
      newValue = 0;
    }

    triggerUpdate(() => {
      // Set Population Dimension Python Side
      Utils.evalPythonMessage('netpyne_geppetto.netParams.popParams.setParam', [
        modelName,
        dimensionType || dimension,
        newValue,
      ])
        .then(() => {
          if (callback) {
            callback();
          }
        })
        .catch((error) => {
          console.error('Error setting dimension:', error);
        });
    });
  };

  const handleDimensionChange = (event: any): void => {
    setDimension(event.target.value);
  };

  return (
    <StyledContainer>
      <NetPyNEField id="netParams.popParams.numCells" sx={{ width: '100%' }}>
        <FormControl fullWidth>
          <InputLabel>
            <Box mt={1} ml={2}>
              Dimension type
            </Box>
          </InputLabel>
          <Select
            fullWidth
            variant="filled"
            value={dimension}
            onChange={handleDimensionChange}
          >
            {popDimensionsOptions.map((popDimensionsOption) => (
              <MenuItem
                id={`popParamS${popDimensionsOption.value}`}
                key={popDimensionsOption.value}
                value={popDimensionsOption.value}
              >
                {popDimensionsOption.label}
              </MenuItem>
            ))}
          </Select>
        </FormControl>
      </NetPyNEField>
      {dimension !== undefined && dimension !== '' && (
        <Box ml={1}>
          {dimension === 'cellsList' ? (
            <ListComponent
              model={`netParams.popParams['${modelName}']['${dimension}']`}
              realType="list(dict)"
            />
          ) : (
            <NetPyNEField id={`netParams.popParams.${dimension}`} sx={{ width: '95%', marginLeft: 3 }}>
              <NetPyNETextField
                fullWidth
                variant="filled"
                handleChange={handleDimValueChange}
                model={`netParams.popParams['${modelName}']['${dimension}']`}
                modelName={modelName}
                dimensionType={dimension}
                callback={(newValue?: any, oldValue?: any) => {
                  if (updateCards) {
                    updateCards();
                  }
                }}
              />
            </NetPyNEField>
          )}
        </Box>
      )}
    </StyledContainer>
  );
};

export default Dimensions;

